import jplur
import jplur.tables as tables

from random import randint, choice
import time

class Entity:
	def __init__(self):
		self.id = jplur.unique_id.new()
		self.name = "the creature"
		self.species = "creature"
		self.desc = "The proto creature, you shouldn't be seeing this."
		self.level = 1
		self.size = 10
		self.speed = .4
		
		self.str = 10
		self.int = 10
		self.con = 10
		self.dex = 10
		
		self.flags = []
		self.hit_die = [5,5] #5d5
		self.attack_die =[1,4]
		
		self.symbol = 'r'
		self.color = "ffffff"
		
		self.location = [0,0,0]
		self.role = 'entity'
		
		self.key = 0
		self.update = time.time()
		self.hp = 30
		self.maxhp = 30
		
		self.exp = 0
		
	def insert(self):
		if self not in jplur.map.entity_hash.query(self.location):
			jplur.map.entity_hash.insert(self)
	
	
	
	def move(self, point):

		oldloc = self.location
		newloc = [self.location[0]+point[0], self.location[1]+point[1], self.location[2]+point[2]]
		if not (newloc[0] >= 0 and newloc[0] <= len(jplur.map.map)-1 and newloc[1] >= 0 and newloc[1] < jplur.map.dimension[0] and newloc[2] >= 0 and newloc[2] < jplur.map.dimension[1]):
			if self.role == 'player':
				self.send( {"action":"message", "data":"#:00bcd8You can't move in that direction." } )
			return
		if jplur.map.map[newloc[0]][newloc[1]][newloc[2]] > 0:
			if self.role == 'player':
				self.send( {"action":"message", "data":"#:00bcd8You bump into the wall." } )
			return
		if jplur.map.map[newloc[0]][newloc[1]][newloc[2]] == 0:
			if self.role == 'player':
				self.send( {"action":"message", "data":"#:00bcd8You can't fly, dude." } )
			return
		bump = jplur.map.things_in_tile(newloc)
		if self.role=='player':
			print "BUMP:",bump
		if self in bump:
			bump.remove(self)
		if len(bump) > 0:
			if self.role == 'player':
				self.send( {"action":"message", "data":"#:00bcd8You bump into "+bump[0].name+"." } )
			return
		self.location = newloc
		
		if self.role == 'player':
			self.send( {"action":"p", "data":self.location } )
		
		players = []
		
		newkey = jplur.map.entity_hash.key(self.location)
		if self.role == 'player':
			print "move!!!!!, ",self.key, newkey
		if newkey != self.key:
			if self.key != 0:
			
			

				#updating hash
				last = jplur.map.entity_hash.query_key(self.key)
				if self in last:
					last.remove(self)
			self.key = newkey
			##########
			self.insert()
			##########
			
			#new sectors
			#let players know i'm not on their screen
			opoint = [point[0]*-1, point[1]*-1, point[2]*-1]
			
			tertloc = self.location
			if point in [ [-1,0,0], [1,0,0] ]:
				tertloc = oldloc
			left_cells = jplur.map.cell_change_view_keys(tertloc, opoint)

			for left_key in left_cells:
				
				players += self.players_in_cell(left_key)
					
					
			if self.role == 'player':  ####discover new cells 

				tertloc = self.location
				if point in [ [-1,0,0], [1,0,0] ]:
					tertloc = oldloc
				new_cells = jplur.map.cell_change_view(tertloc, point)
				print "should be looking at cells around:", point
				self.view( new_cells )
				
				## now lets find out what's in these new cells
				total_things = []
				for entry in new_cells:
					for found in jplur.map.entity_hash.query_key(entry[0]):
						total_things.append( [found.id, found.symbol, found.color, found.location] )
				if len(total_things) > 0:
					
					self.send( {"action":"m", "data":total_things})
		
		#now tell players nearby i've moved
		
		for i in range(3):
			for j in range(3):
				cell_key = (self.key[0], self.key[1]+i-1, self.key[2]+j-1)
				
				players += self.players_in_cell(cell_key)
						
		
		for entry in players:
			entry.send( {"action":"m", "data":[[self.id, self.symbol, self.color, self.location]]})
		
	def players_in_cell(self, key):
		players = []
		for entry in jplur.map.entity_hash.query_key(key):
				if entry.role == "player":
					players.append(entry)
		return players
		
	def closest_of_role(self, role):
		candidates = []
		closest = [10000000,0] #best yet, distance, entity
		for entry in jplur.map.cell_change_view_keys(self.location, [0,0,0]):
				found = jplur.map.entity_hash.query_key(entry)
				for entry in found:
					
					if entry != self:
						if entry.role == role:

							candidates.append(entry)
		for entry in candidates:
			dist = jplur.map.entity_hash.get_distance(self.location, entry.location)
			if dist < closest[0]:
				closest = [dist, entry]
		
		if len(candidates) > 0:
			return closest[1]
			
	def get_adjacent_role(self, role):
		dirs = [ [0,-1,-1], [0,0,-1], [0,1,-1], [0,-1,0], [0,1,0], [0,-1,1], [0,0,1], [0,1,1] ]
		for entry in dirs:
			litloc = [self.location[0],self.location[1]+entry[1], self.location[2]+entry[2]]
			found = jplur.map.things_in_tile(litloc)
			for thing in found:
				if thing.role == role:
					return thing
		
	def flow_to(self, point): #or could be entity111
		if type(point) != list:
			goal = point.location
		else:
			goal = point
		x = 0
		y = 0
		if self.location[1] < goal[1]:
			x = 1
		if self.location[1] > goal[1]:
			x = -1
		if self.location[2] < goal[2]:
			y = 1
		if self.location[2] > goal[2]:
			y = -1
		ideal = [0,x,y]
		
		possible= [ideal]
		oideal = [ideal[0],ideal[1]*-1,ideal[2]*-1]
		possible += tables.leave_behind()[ tuple(ideal)]
		for entry in possible:
			litentry = [self.location[0],self.location[1]+entry[1],self.location[2]+entry[2]]
			if not ( len(jplur.map.things_in_tile(litentry)) > 0 or jplur.map.tile_at(litentry) >= 0 ):
				return entry	
	
	def roll(self, dice):
		total = 0
		for i in range(dice[0]):
			total += randint(1,dice[1])
		return total
		
	def attack(self, other):
		offense = self.dex*10+self.level*3
		defense = other.dex*10+other.level*3
		print "O:",randint(1,offense), " D:",randint(1,defense)
		if randint(1,offense) > randint(1,defense):
			return self.roll(self.attack_die)
			
	def die(self,bywho):
		#let players know i'm out of here.
		
		#assign experience
		
		bywho.exp += self.level*self.level
		
		for player in self.players_in_cell(self.key):
			if player != self:
				player.send({"action":"message","data":"#:ff7e00"+self.name[:1].upper()+self.name[1:]+" was killed by "+bywho.name+"."})
				player.send({"action":"remove", "data":self.id})
				
			if self.role == 'player':
				jplur.server.SendToAll({"action":"message","data":"#:e400ff"+self.name+" was killed by "+bywho.name+"!"})
				
		last = jplur.map.entity_hash.query_key(self.key)
		if self in last:
			last.remove(self)
				
		if self in jplur.monsters:
			jplur.monsters.remove(self)
			
		if self in jplur.players:
			jplur.players.remove(self)
			
			menu_die(self.channel)
		
class Human(Entity):
	def __init__(self):
		Entity.__init__(self)
		print "Human class init"
		self.species = "human"
		self.name = "anon"
		
		self.flags += []
		
class Monster(Entity):
	def __init__(self, packet):	
		Entity.__init__(self)
		

		self.species = packet[0]
		self.name = packet[1]
		self.level = packet[2]
		self.size = packet[3]
		self.speed = packet[4]
		self.str = packet[5]
		self.intel = packet[6]
		self.con = packet[7]
		self.dex = packet[8]
		self.flags = packet[9]
		self.hit_die = packet[10]
		self.symbol = packet[11]
		self.color = packet[12]
		self.attack_die = packet[13]
		
		self.role = "monster"
		
		self.hp = self.roll(self.hit_die)
		self.maxhp = self.hp
	
	
				
		
	def pump(self):
		
		if time.time() - self.update > self.speed:
			self.update = time.time()
			
			#are we standing next to a target?
			found = self.get_adjacent_role("player")
			if found:
				hit = self.attack(found)
				if hit:
					found.send({"action":"message","data":"#:dd2929"+self.name[:1].upper()+self.name[1:]+" hits you for "+str(hit)+"!"})
					found.hp -= hit
					if found.hp <= 0:
						found.die(self)
				else:
					found.send({"action":"message","data":"#:38e1df"+self.name[:1].upper()+self.name[1:]+" misses you!"})
			else: #is there a target to walk towards?
				found = self.closest_of_role("player")
				if found:
					
					dir = self.flow_to(found)
					if dir:
						self.move(dir)
		
